/*
* Copyright (c) 2008, Vladimir Gumenuk
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the copyright holder nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// stdafx.cpp : source file that includes just the standard includes
// RealGNX4Lib.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

//  all GNX strings are 10 chars length!!!

void StoreGNXStringA( CHAR *pszDst, LPCSTR lpszSrc )
{
    ASSERT( pszDst ); ASSERT( lpszSrc );

    size_t iLen = strlen( lpszSrc );
    if( iLen > 10 )
        iLen = 10;

    for( UINT i = 0; i < iLen; i++ )
        pszDst[i] = lpszSrc[i];

    for( ; iLen < 10; iLen++ )
        pszDst[iLen] = 0x20;

    pszDst[10] = 0;
}

void StoreGNXStringW( WCHAR *pszDst, LPCWSTR lpszSrc )
{
    ASSERT( pszDst ); ASSERT( lpszSrc );

    size_t iLen = wcslen( lpszSrc );
    if( iLen > 10 )
        iLen = 10;

    for( UINT i = 0; i < iLen; i++ )
        pszDst[i] = lpszSrc[i];

    for( ; iLen < 10; iLen++ )
        pszDst[iLen] = (WCHAR)0x0020;

    pszDst[10] = 0;
}

CString GNXAssignCodeToStr( DWORD dwCode )
{
    switch( dwCode )
    {
    case ASGN_None:                        return "None";
    case ASGN_Amp_Chanel:                  return "Amp Chanel";
    case ASGN_Amp_Warp:                    return "Amp Warp";
    case ASGN_Cabinet_Warp:                return "Cabinet Warp";
    case ASGN_Warp:                        return "Warp";
    case ASGN_Chan1_AmpGain:               return "Chan. 1 Amp Gain";
    case ASGN_Chan1_AmpLevel:              return "Chan. 1 Amp Level";
    case ASGN_Chan2_AmpGain:               return "Chan. 2 Amp Gain";
    case ASGN_Chan2_AmpLevel:              return "Chan. 2 Amp Level";
    case ASGN_Wah_Enable:                  return "Wah Enable";
    case ASGN_Wah_Position:                return "Wah Position";
    case ASGN_Pickup_Enable:               return "Pickup Enable";
    case ASGN_Pickup_Type:                 return "Pickup Type";
    case ASGN_Compressor_Enable:           return "Compressor Enable";
    case ASGN_Compressor_Attack:           return "Compressor Attack";
    case ASGN_Compressor_Ratio:            return "Compressor Ratio";
    case ASGN_Compressor_Threshould:       return "Compressor Threshould";
    case ASGN_Compressor_Gain:             return "Compressor Gain";
    case ASGN_WhamISPMod_Enable:           return "Wham/ISP/Mod Enable";
        case ASGN_Whammy_Pedal:                return "Whammy Pedal";
        case ASGN_Detune_Amount:               return "Detune Amount";
    case ASGN_Talker_MicLevel:             return "Talker Mic Level";
    case ASGN_StompBox_Enable:             return "StompBox Enable";
    case ASGN_StompBox_Distortion:         return "StompBox Distortion";
    case ASGN_StompBox_MidFreq:            return "StompBox Mid Freq";
    case ASGN_StompBox_MidLevel:           return "StompBox Mid Level";
    case ASGN_StompBox_Level:              return "StompBox Level";
    case ASGN_StompBox_Low:                return "StompBox Low";
    case ASGN_StompBox_High:               return "StompBox High";
    case ASGN_Gate_Enable:                 return "Gate Enable";
    case ASGN_Gate_Threshould:             return "Gate Threshould";
    case ASGN_Gate_Attack:                 return "Gate Attack";
    case ASGN_Gate_PluckSens:              return "Gate Pluck Sens.";
    case ASGN_Mod_Enable:                  return "Mod Enable";
    case ASGN_Rotary_Speed:                return "Rotary Speed";
    case ASGN_Rotary_Depth:                return "Rotary Depth";
    case ASGN_Rotary_Doppler:              return "Rotary Doppler";
    case ASGN_Rotary_Mix:                  return "Rotary Mix";
    case ASGN_Rotary_XOver:                return "Rotary X-Over";
    case ASGN_Rotary_Balance:              return "Rotary Balance";
    case ASGN_Delay_Enable:                return "Delay Enable";
    case ASGN_Delay_Feedback:              return "Delay Feedback";
    case ASGN_Delay_DuckThresh:            return "Delay Duck Thresh.";
    case ASGN_Delay_DuckAtten:             return "Delay Duck Atten.";
    case ASGN_Delay_Level:                 return "Delay Level";
    case ASGN_Delay_Balance:               return "Delay Balance";
    case ASGN_Reverb_Enable:               return "Reverb Enable";
    case ASGN_Reverb_Predelay:             return "Reverb Predelay";
    case ASGN_Reverb_Decay:                return "Reverb Decay";
    case ASGN_Reverb_Level:                return "Reverb Level";
    case ASGN_Reverb_Balance:              return "Reverb Balance";
    case ASGN_Volume_PedalPreFX:           return "Volume Pedal Pre FX";
    case ASGN_Volume_PedalPostFX:          return "Volume Pedal Post FX";
    case ASGN_LFO1_Speed:                  return "LFO1 Speed";
    case ASGN_LFO2_Speed:                  return "LFO2 Speed";
    default:
        TRACE( "Unknown ASSGN CODE: 0x%08X\n", dwCode );
        //ASSERT( 0 );
#pragma message("-> !!! REVERSE ALL ASSIGN CODES AND FIX ME !!! <-\n")
        return "Unknown";
        
    }

    return CString( _T("") );
}

void PrintHexDump( LPBYTE buffer, DWORD Length )
{
    static const CHAR  rgbDigits[] = "0123456789ABCDEF";

    DWORD i, count, index;
    CHAR  szLine[128];
    int   cbLine;

    for( index = 0; Length; Length -= count, buffer += count, index += count )
    {
        count = (Length > 16) ? 16: Length;
        cbLine = 0;
        DWORD dwAddrr = index;
        LPBYTE pA = (LPBYTE)&dwAddrr;

        szLine[cbLine++] = '*';
        szLine[cbLine++] = ' ';

        // fast replacement for sprintf... sprintf_s( szLine, "%08X: ", dwAddrrBase + index );
        szLine[cbLine++] = rgbDigits[pA[3] >> 4];
        szLine[cbLine++] = rgbDigits[pA[3] & 0x0f];
        szLine[cbLine++] = rgbDigits[pA[2] >> 4];
        szLine[cbLine++] = rgbDigits[pA[2] & 0x0f];
        szLine[cbLine++] = rgbDigits[pA[1] >> 4];
        szLine[cbLine++] = rgbDigits[pA[1] & 0x0f];
        szLine[cbLine++] = rgbDigits[pA[0] >> 4];
        szLine[cbLine++] = rgbDigits[pA[0] & 0x0f];
        szLine[cbLine++] = ':';
        szLine[cbLine++] = ' ';

        for( i = 0; i < count; i++ )
        {
            szLine[cbLine++] = rgbDigits[buffer[i] >> 4];
            szLine[cbLine++] = rgbDigits[buffer[i] & 0x0f];

            if( i == 7 )  {
                szLine[cbLine++] = ' ';
                szLine[cbLine++] = ' ';
            } else 
                szLine[cbLine++] = ' ';
        }
        if( i < 16 )
            szLine[cbLine++] = ' ';
        for( ; i < 16; i++ ) 
        {
            szLine[cbLine++] = ' ';
            szLine[cbLine++] = ' ';
            szLine[cbLine++] = ' ';
        }
        for( i = 0; i < count; i++ )
        {
            if( buffer[i] < 0x20 || buffer[i] > 0x80 )
                szLine[cbLine++] = '.';
            else 
                szLine[cbLine++] = buffer[i];
        }

        //szLine[cbLine++] = '\r';
        //szLine[cbLine++] = '\n';
        szLine[cbLine++] = 0; 

        TRACE( "%s\n", szLine );
    }
}

void SetPresetDefaults( LPPRESET p )
{
    ZeroMemory( p, sizeof(PRESET) );
/*
    p->wUnknown1 = 0;       // always 0
    p->wUnknown2 = 0;       // 0, very rarely 0x63
    p->wUnknown3 = 0;       // always 0
    p->wUnknown4 = 8;       // range: 1 - 0x0F
    p->wUnknown5 = 8;       // range: 0 - 0x0F
    p->wUnknown6 = 8;       // range: 2 - 0x13
    p->wUnknown7 = 8;       // range: 1 - 0x0F
    p->wUnknown8 = 0x63;    // always 0x63
    p->wUnknown9 = 0x63;    // always 0x63
    p->wUnknown10 = 0;      // always 0
    p->wUnknown11 = 0;      // always 0
    p->wUnknown12 = 0;      // 0-1, 1 - very rarely
    p->wUnknown13 = 0;      // always 0
    p->wUnknown14 = 0x81;   // always 0x81
    p->wUnknown15 = 3;      // always 3
    p->wUnknown16 = 0;      // always 0
    p->wUnknown17 = 1;      // a;ways 1
    p->wUnknown18 = 0;      // always 0
    p->wUnknown19 = 0;      // always 0
    p->wUnknown20 = 0;      // always 0
    p->wUnknown21 = 0;      // always 0
    p->wUnknown22 = 0;      // always 0
    p->wUnknown23 = 0;      // always 0
    p->wUnknown24 = 0;      // always 0
    p->wUnknown25 = 0;      // always 0
    p->wUnknown26 = 0x84;   // always 0x84
    p->wUnknown27 = 3;      // always 3
    p->wUnknown28 = 0;      // always 0
    p->wUnknown29 = 0;      // always 0
    p->wUnknown30 = 0;      // always 0
    p->wUnknown31 = 0;      // always 0
    p->wUnknown32 = 0;      // always 0
    p->wUnknown33 = 0;      // always 0
    p->wUnknown34 = 0;      // always 0
    p->wUnknown35 = 0;      // always 0
*/
    // unknown data block - taken from 1 std preset
/*    static const WORD s_Blk[60] = {
        0x0010,0x0000,0xFFE0,0x5878,0x000F,0xA962,0x001F,0xA788,0xFFF0,0x569E,0x0011,0x6677,0xFFE3,0xE071,0x000B,0xC92F,
        0x001C,0x1F8F,0xFFF2,0xD05A,0x0012,0xB765,0xFFED,0x10A2,0x0006,0x4D97,0x0012,0xEF5E,0xFFF6,0xFB03,0x000F,0xEBEF,
        0xFFE0,0x6E97,0x000F,0xA752,0x001F,0x9169,0xFFF0,0x6CBF,0x0010,0x0000,0xFFE2,0xF49B,0x000D,0x7967,0x001D,0x0B65,
        0xFFF2,0x8699,0x0011,0x92DB,0xFFED,0x8E4F,0x0006,0xCC11,0x0012,0x71B1,0xFFF7,0xA113
    };

    memcpy( &p->wUnkData[0], &s_Blk[0], 120 );
    */
}


void DumpGNXAmp( const GNX_AMP *pAmp )
{
    USES_CONVERSION;
    TRACE( "---> GNX AMP: '%s' <---\n", W2A(pAmp->wszName) );

    TRACE( "SPLINE COEFICIENTS:" );
    for( DWORD i = 0; i < NUM_SPLINE_COEFS; i++ )
    {
        if( i % 16 == 0 )
            TRACE( "\n" );
        TRACE( "0x%08X ", pAmp->dwSplineCoefData[i] );
    }
    TRACE( "\n" );

    TRACE( "MODEL EQ ZReg DATA:" );
    for( DWORD i = 0; i < NUM_MODEL_EQ_ZREGS; i++ )
    {
        if( i % 16 == 0 )
            TRACE( "\n" );
        TRACE( "0x%08X ", pAmp->dwModelEqZRegData[i] );
    }
    TRACE( "\n" );

    TRACE( "AMP DEF TONE:\n" );
    TRACE( "wBass_Freq: 0x%04X\n", pAmp->def_Tone.wBass_Freq );
    TRACE( "wMid_Freq: 0x%04X\n", pAmp->def_Tone.wMid_Freq );
    TRACE( "wHi_Freq: 0x%04X\n", pAmp->def_Tone.wHi_Freq );
    TRACE( "wBass_Level: 0x%04X\n", pAmp->def_Tone.wBass_Level );
    TRACE( "wMid_Level: 0x%04X\n", pAmp->def_Tone.wMid_Level );
    TRACE( "wHi_Level: 0x%04X\n", pAmp->def_Tone.wHi_Level );
    TRACE( "wPresence: 0x%04X\n", pAmp->def_Tone.wPresence );
    TRACE( "wAmp_Gain: 0x%04X\n", pAmp->def_Tone.wAmp_Gain );
    TRACE( "wAmp_Level: 0x%04X\n", pAmp->def_Tone.wAmp_Level );

    TRACE( "AMP DEF RANGE:\n" );
    TRACE( "dwGain_Max: 0x%08X\n", pAmp->def_Range.dwGain_Max );
    TRACE( "dwGain_Min: 0x%08X\n", pAmp->def_Range.dwGain_Min );
    TRACE( "dwLevel_Max: 0x%08X\n", pAmp->def_Range.dwLevel_Max );
    TRACE( "dwLevel_Min: 0x%08X\n", pAmp->def_Range.dwLevel_Min );

    TRACE( "DUMMY: 0x%04X\n", pAmp->wDummy );

    TRACE( "-----------------------------------------------------------\n" );
}

BOOL CompareAmpModels( const GNX_AMP *pAmp1, const GNX_AMP* pAmp2 )
{
    BOOL bRet = TRUE;
    for( DWORD i = 0; i < NUM_SPLINE_COEFS; i++ )
    {
        if( pAmp1->dwSplineCoefData[i] != pAmp2->dwSplineCoefData[i] )
        {
            TRACE( "Spline Coefs differs at %d, 0x%08X - 0x%08X\n", i, pAmp1->dwSplineCoefData[i], pAmp2->dwSplineCoefData[i] );
            bRet = FALSE;
        }
    }

    for( DWORD i = 0; i < NUM_MODEL_EQ_ZREGS; i++ )
    {
        if( pAmp1->dwModelEqZRegData[i] != pAmp2->dwModelEqZRegData[i] )
        {
            TRACE( "Model EQ ZRegData differs at %d, 0x%08X - 0x%08X\n", i, pAmp1->dwModelEqZRegData[i], pAmp2->dwModelEqZRegData[i] );
            bRet = FALSE;
        }
    }

    if( pAmp1->def_Tone.wBass_Freq != pAmp2->def_Tone.wBass_Freq )
    {
        TRACE( "!= wBass_Freq: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wBass_Freq, pAmp2->def_Tone.wBass_Freq );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wMid_Freq != pAmp2->def_Tone.wMid_Freq )
    {
        TRACE( "!= wMid_Freq: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wMid_Freq, pAmp2->def_Tone.wMid_Freq );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wHi_Freq != pAmp2->def_Tone.wHi_Freq )
    {
        TRACE( "!= wHi_Freq: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wHi_Freq, pAmp2->def_Tone.wHi_Freq );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wBass_Level != pAmp2->def_Tone.wBass_Level )
    {
        TRACE( "!= wBass_Level: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wBass_Level, pAmp2->def_Tone.wBass_Level );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wMid_Level != pAmp2->def_Tone.wMid_Level )
    {
        TRACE( "!= wMid_Level: 0x%04X\n", pAmp1->def_Tone.wMid_Level, pAmp2->def_Tone.wMid_Level );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wHi_Level != pAmp2->def_Tone.wHi_Level )
    {
        TRACE( "!= wHi_Level: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wHi_Level, pAmp2->def_Tone.wHi_Level );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wPresence != pAmp2->def_Tone.wPresence )
    {
        TRACE( "!= wPresence: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wPresence, pAmp2->def_Tone.wPresence );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wAmp_Gain != pAmp2->def_Tone.wAmp_Gain )
    {
        TRACE( "!= wAmp_Gain: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wAmp_Gain, pAmp2->def_Tone.wAmp_Gain );
        bRet = FALSE;
    }

    if( pAmp1->def_Tone.wAmp_Level != pAmp2->def_Tone.wAmp_Level )
    {
        TRACE( "!= wAmp_Level: 0x%04X - 0x%04X\n", pAmp1->def_Tone.wAmp_Level, pAmp2->def_Tone.wAmp_Level );
        bRet = FALSE;
    }

    if( pAmp1->def_Range.dwGain_Max != pAmp2->def_Range.dwGain_Max )
    {
        TRACE( "!= dwGain_Max: 0x%08X - 0x%08X\n", pAmp1->def_Range.dwGain_Max, pAmp2->def_Range.dwGain_Max );
        bRet = FALSE;
    }

    if( pAmp1->def_Range.dwGain_Min != pAmp2->def_Range.dwGain_Min )
    {
        TRACE( "!= dwGain_Min: 0x%08X - 0x%08X\n", pAmp1->def_Range.dwGain_Min, pAmp2->def_Range.dwGain_Min );
        bRet = FALSE;
    }

    if( pAmp1->def_Range.dwLevel_Max != pAmp2->def_Range.dwLevel_Max )
    {
        TRACE( "!= dwLevel_Max: 0x%08X - 0x%08X\n", pAmp1->def_Range.dwLevel_Max, pAmp2->def_Range.dwLevel_Max );
        bRet = FALSE;
    }

    if( pAmp1->def_Range.dwLevel_Min != pAmp2->def_Range.dwLevel_Min )
    {
        TRACE( "!= dwLevel_Min: 0x%08X - 0x%08X\n", pAmp1->def_Range.dwLevel_Min, pAmp2->def_Range.dwLevel_Min );
        bRet = FALSE;
    }

    if( pAmp1->wDummy != pAmp2->wDummy )
    {
        TRACE( "!= DUMMY: 0x%04X - 0x%04X\n", pAmp1->wDummy, pAmp2->wDummy );
        bRet = FALSE;
    }

    return bRet;
}

BOOL ComparePresets( const LPPRESET pPr1, const LPPRESET pPr2 )
{
    BOOL bRet = TRUE;

    TRACE( "Comparing pressets: '%S' & '%S'...\n", pPr1->wszName, pPr2->wszName );

#define COMPARE_PARAM(x) \
    { if( pPr1->x != pPr2->x ) { \
        TRACE( "!= " #x ":" ); TRACE( " 0x%04X - 0x%04X\n", pPr1->x, pPr2->x ); \
        bRet = FALSE; } }

    COMPARE_PARAM( wPICKUP_Type );
    COMPARE_PARAM( wWAH_OnOff );
    COMPARE_PARAM( wWAH_Type );
    COMPARE_PARAM( wWAH_Pedal );
    COMPARE_PARAM( wCOMPRESSOR_OnOff );
    COMPARE_PARAM( wCOMPRESSOR_Type );
    COMPARE_PARAM( wCOMPRESSOR_Atack );
    COMPARE_PARAM( wCOMPRESSOR_Threshould );
    COMPARE_PARAM( wCOMPRESSOR_Ratio );
    COMPARE_PARAM( wCOMPRESSOR_Gain ); 
    COMPARE_PARAM( wWHAMMY_IPS_TALK_OnOff ); 
    COMPARE_PARAM( wWHAMMY_IPS_TALK_Selection );
    COMPARE_PARAM( wWHAMMY_IPS_PITCH_DETUNER_Level ); 
    COMPARE_PARAM( wWHAMMY_Parameter1 ); 
    COMPARE_PARAM( wWHAMMY_Parameter2 ); 
    COMPARE_PARAM( wIPS_Key );           
    COMPARE_PARAM( wWHAM_PEDAL );       
    COMPARE_PARAM( wActiveChanel );     
    COMPARE_PARAM( wEQ_Channel );       
    COMPARE_PARAM( wGreen_AMP_Type );   
    COMPARE_PARAM( wGreen_TONEAMP_Gain );
    COMPARE_PARAM( wGreen_TONEAMP_Level );
    COMPARE_PARAM( wGreen_CAB_Type );   
    COMPARE_PARAM( wGreen_CABTUNE );       
    COMPARE_PARAM( wGreen_BASS_Freq );     
    COMPARE_PARAM( wGreen_TONE_BASS );     
    COMPARE_PARAM( wGreen_MID_Freq );      
    COMPARE_PARAM( wGreen_TONE_Midrange ); 
    COMPARE_PARAM( wGreen_TREB_Freq );     
    COMPARE_PARAM( wGreen_TONE_TREBE );    
    COMPARE_PARAM( wRed_AMP_Type ); 
    COMPARE_PARAM( wRed_TONEAMP_Gain );    
    COMPARE_PARAM( wRed_TONEAMP_Level );   
    COMPARE_PARAM( wRed_CAB_Type ); 
    COMPARE_PARAM( wRed_CABTUNE );         
    COMPARE_PARAM( wRed_BASS_Freq );       
    COMPARE_PARAM( wRed_TONE_BASS );       
    COMPARE_PARAM( wRed_MID_Freq );        
    COMPARE_PARAM( wRed_TONE_Midrange );   
    COMPARE_PARAM( wRed_TREB_Freq );       
    COMPARE_PARAM( wRed_TONE_TREBE );      
    COMPARE_PARAM( wNOISEGATE_OnOff );     
    COMPARE_PARAM( wNOISEGATE_Type );      
    COMPARE_PARAM( wNOISEGATE_Threshould );
    COMPARE_PARAM( wNOISEGATE_Attack );    
    COMPARE_PARAM( wNOISEGATE_Pluck_Sensitivity );
    COMPARE_PARAM( wCHORUSMOD_OnOff );         
    COMPARE_PARAM( wCHORUSMOD_Type );          
    COMPARE_PARAM( wCHORUSMOD_Level );         
    COMPARE_PARAM( wCHORUSMOD_Param1 );        
    COMPARE_PARAM( wCHORUSMOD_Param2 );        
    COMPARE_PARAM( wCHORUSMOD_Param3 );        
    COMPARE_PARAM( wCHORUSMOD_Param4 );        
    COMPARE_PARAM( wCHORUSMOD_Param5 );        
    COMPARE_PARAM( wDELAY_OnOff );             
    COMPARE_PARAM( wDELAY_Type );              
    COMPARE_PARAM( wDELAY_Level );             
    COMPARE_PARAM( wDELAY_Time );              
    COMPARE_PARAM( wDELAY_Feedback );          
    COMPARE_PARAM( wDELAY_Threshould );        
    COMPARE_PARAM( wDELAY_Attenuation );       
    COMPARE_PARAM( wDELAY_LRBalance );         
    COMPARE_PARAM( wREVERB_OnOff );            
    COMPARE_PARAM( wREVERB_Type );             
    COMPARE_PARAM( wREVERB_Level );            
    COMPARE_PARAM( wREVERB_Decay );            
    COMPARE_PARAM( wREVERB_Dumping );          
    COMPARE_PARAM( wREVERB_Predelay );         
    COMPARE_PARAM( wREVERB_LRBalance );        
    COMPARE_PARAM( wWARPY ); 
    COMPARE_PARAM( wWARPX ); 
    COMPARE_PARAM( wWARPZ ); 
    COMPARE_PARAM( wSTOMPBOX_OnOff );          
    COMPARE_PARAM( wSTOMPBOX_Type );           
    COMPARE_PARAM( wSTOMPBOX_Gain );           
    COMPARE_PARAM( wSTOMPBOX_Level );          
    COMPARE_PARAM( wSTOMPBOX_Param1 );         
    COMPARE_PARAM( wSTOMPBOX_Param2 );         
    COMPARE_PARAM( wMZONE_LowFreq );           
    COMPARE_PARAM( wMZONE_HiLevel );           
    COMPARE_PARAM( wVOLUME_Pre ); 
    COMPARE_PARAM( wVOLUME_Post ); 
    COMPARE_PARAM( wEXPPdl1Assign );           
    COMPARE_PARAM( wEXPPdl1Position );
    COMPARE_PARAM( wEXPPdl1Min );              
    COMPARE_PARAM( wEXPPdl1Max );              
    COMPARE_PARAM( wEXPPdl2Assign );           
    COMPARE_PARAM( wEXPPdl2Position );
    COMPARE_PARAM( wEXPPdl2Min );              
    COMPARE_PARAM( wEXPPdl2Max );              
    COMPARE_PARAM( wEXPPdl3Assign );           
    COMPARE_PARAM( wEXPPdl3Position );
    COMPARE_PARAM( wEXPPdl3Min );              
    COMPARE_PARAM( wEXPPdl3Max );              
    COMPARE_PARAM( wLFO1Assign );              
    COMPARE_PARAM( wLFO1Position ); 
    COMPARE_PARAM( wLFO1Min );                 
    COMPARE_PARAM( wLFO1Max );                 
    COMPARE_PARAM( wLFO1Speed );               
    COMPARE_PARAM( wLFO1WaveForm );            
    COMPARE_PARAM( wLFO2Assign );              
    COMPARE_PARAM( wLFO2Position ); 
    COMPARE_PARAM( wLFO2Min );                 
    COMPARE_PARAM( wLFO2Max );                 
    COMPARE_PARAM( wLFO2Speed );               
    COMPARE_PARAM( wLFO2WaveForm );            
    COMPARE_PARAM( wAmpChannelFootSwitch );    
    COMPARE_PARAM( wCTRLA_Type );              
    COMPARE_PARAM( wCTRLA_Lnk1_Assign );       
    COMPARE_PARAM( wCTRLA_Lnk1_Pos ); 
    COMPARE_PARAM( wCTRLA_Lnk1_Min );          
    COMPARE_PARAM( wCTRLA_Lnk1_Max );          
    COMPARE_PARAM( wCTRLA_Lnk2_Assign );       
    COMPARE_PARAM( wCTRLA_Lnk2_Pos ); 
    COMPARE_PARAM( wCTRLA_Lnk2_Min );          
    COMPARE_PARAM( wCTRLA_Lnk2_Max );          
    COMPARE_PARAM( wCTRLA_Lnk3_Assign );       
    COMPARE_PARAM( wCTRLA_Lnk3_Pos );          
    COMPARE_PARAM( wCTRLA_Lnk3_Min );          
    COMPARE_PARAM( wCTRLA_Lnk3_Max );          
    COMPARE_PARAM( wFS_TAPIT_Mode );  
    COMPARE_PARAM( wMODIFIED );       
    COMPARE_PARAM( wDELAY_Spread );            
    COMPARE_PARAM( wPICKUP_OnOff );            
    COMPARE_PARAM( wGreen_EQUALIZER_OnOff );   
    COMPARE_PARAM( wGreen_Presence );          
    COMPARE_PARAM( wRed_EQUALIZER_OnOff );     
    COMPARE_PARAM( wRed_Presence );            
    COMPARE_PARAM( wVSWITCH_State );  
    COMPARE_PARAM( wPresetLevel );             
    COMPARE_PARAM( wCTRLB_Type );              
    COMPARE_PARAM( wCTRLB_Lnk1_Assign );       
    COMPARE_PARAM( wCTRLB_Lnk1_Pos ); 
    COMPARE_PARAM( wCTRLB_Lnk1_Min );          
    COMPARE_PARAM( wCTRLB_Lnk1_Max );          
    COMPARE_PARAM( wCTRLB_Lnk2_Assign );       
    COMPARE_PARAM( wCTRLB_Lnk2_Pos ); 
    COMPARE_PARAM( wCTRLB_Lnk2_Min );          
    COMPARE_PARAM( wCTRLB_Lnk2_Max );          
    COMPARE_PARAM( wCTRLB_Lnk3_Assign );       
    COMPARE_PARAM( wCTRLB_Lnk3_Pos ); 
    COMPARE_PARAM( wCTRLB_Lnk3_Min );          
    COMPARE_PARAM( wCTRLB_Lnk3_Max );          
    COMPARE_PARAM( wCTRLC_Type );              
    COMPARE_PARAM( wCTRLC_Lnk1_Assign );       
    COMPARE_PARAM( wCTRLC_Lnk1_Pos ); 
    COMPARE_PARAM( wCTRLC_Lnk1_Min );          
    COMPARE_PARAM( wCTRLC_Lnk1_Max );          
    COMPARE_PARAM( wCTRLC_Lnk2_Assign );       
    COMPARE_PARAM( wCTRLC_Lnk2_Pos ); 
    COMPARE_PARAM( wCTRLC_Lnk2_Min );          
    COMPARE_PARAM( wCTRLC_Lnk2_Max );          
    COMPARE_PARAM( wCTRLC_Lnk3_Assign );       
    COMPARE_PARAM( wCTRLC_Lnk3_Pos ); 
    COMPARE_PARAM( wCTRLC_Lnk3_Min );          
    COMPARE_PARAM( wCTRLC_Lnk3_Max );          
    COMPARE_PARAM( wVSW_FS_Type );
    COMPARE_PARAM( wVSW1_FS_Param );
    COMPARE_PARAM( wVSW1_FS_Pos );
    COMPARE_PARAM( wVSW1_FS_Min );
    COMPARE_PARAM( wVSW1_FS_Max );
    COMPARE_PARAM( wVSW2_FS_Param );
    COMPARE_PARAM( wVSW2_FS_Pos );
    COMPARE_PARAM( wVSW2_FS_Min );
    COMPARE_PARAM( wVSW2_FS_Max );
    COMPARE_PARAM( wVSW3_FS_Param );
    COMPARE_PARAM( wVSW3_FS_Pos );
    COMPARE_PARAM( wVSW3_FS_Min );
    COMPARE_PARAM( wVSW3_FS_Max );
    COMPARE_PARAM( wWAH_Pdl1_Param );
    COMPARE_PARAM( wWAH_Pdl1_Pos );
    COMPARE_PARAM( wWAH_Pdl1_Min );            
    COMPARE_PARAM( wWAH_Pdl1_Max );            
    COMPARE_PARAM( wWAH_Pdl2_Param );
    COMPARE_PARAM( wWAH_Pdl2_Pos );
    COMPARE_PARAM( wWAH_Pdl2_Min );
    COMPARE_PARAM( wWAH_Pdl2_Max );
    COMPARE_PARAM( wWAH_Pdl3_Param );
    COMPARE_PARAM( wWAH_Pdl3_Pos );
    COMPARE_PARAM( wWAH_Pdl3_Min );
    COMPARE_PARAM( wWAH_Pdl3_Max );

    if( !bRet )
    {
        TRACE( "Preset parameters != \n" );
    }

    if( !CompareAmpModels( &pPr1->Amp1, &pPr2->Amp1 ) )
    {
        TRACE( "Amp models 1 != \n" );            
        bRet = FALSE;
    }

    if( !CompareAmpModels( &pPr1->Amp2, &pPr2->Amp2 ) )
    {
        TRACE( "Amp models 2 != \n" );
        bRet = FALSE;
    }

    for( DWORD i = 0; i < NUM_CAB_ZREGS; i++ )
    {
        if( pPr1->Cab1Data[i] != pPr2->Cab1Data[i] )
        {
            TRACE( "!= Cab1Data at %d, 0x%04X - 0x%04X\n", i, pPr1->Cab1Data[i], pPr2->Cab1Data[i] );
            bRet = FALSE;
        }
    }

    for( DWORD i = 0; i < NUM_CAB_ZREGS; i++ )
    {
        if( pPr1->Cab2Data[i] != pPr2->Cab2Data[i] )
        {
            TRACE( "!= Cab2Data at %d, 0x%04X - 0x%04X\n", i, pPr1->Cab2Data[i], pPr2->Cab2Data[i] );
            bRet = FALSE;
        }
    }

    if( bRet )
    {
        TRACE( "PRESETS ARE EQUAL!!!\n" );
    }

    // DO I need to compare PROGRAM_EQ?? it seems that this is unmodifiable data, or calculated dynamically?

    return bRet;
}